#ifndef _WORDPAGES_H
#define _WORDPAGES_H
#include <tool/ydefine.h>
#include <tool/ystr.h>

/** Type wordPages' page state, 
use by <code>addPage(..)</code> function pointer */
typedef enum wordPagesPageState {wpFail, wpSuccess, wpIgnored} wpState;

/** Function pointers struct, use externally */
typedef struct wordPagesFn *wordPagesFn;
/** Data struct, use internally */
typedef struct wordPages *wordPages;
/** Data struct, use internally */
typedef struct wordPagesFnData *wordPagesFnData;

/** struct of wordPages function pointers */
struct wordPagesFn {
  /*--- data ---*/
  wordPagesFnData d;
  /*--- function pointers ---*/
  /** Create a wordPages with this word.
  Will create another copy of this word (clone of), 
  will NOT use the passed in string.
  @param fn the <code>wordPagesFn</code> to use.
  @param word pass in the word.
  @param aPage the page number to add.
  @return created wordPages.
  */
  wordPages (*create)(wordPagesFn fn, const char *word, 
      const char *aPage);
  /** Create a wordPages with this word and this word has this length.
  Will create another copy of this word (clone of), 
  Will create another copy of this page (clone of), 
  will NOT use the passed in string.
  @param fn the <code>wordPagesFn</code> to use.
  @param word pass in the word.
  @param wordLen the length of the <code>word</code>.
  @param aPage the page number to add.
  @return a created wordPages or <code>NULL</code> if failure.
  */
  wordPages (*createWith)(wordPagesFn fn, const char *word, 
      const unsigned int wordLen, const char *aPage);
  /** Set <code>wordPagesFn</code>'s <code>strFn</code>.
  If <code>strFn</code> is already created, 
  this action will be ignored and <code>false</code> will be returned.
  <code>wordPagesFn</code> will NOT free the memory of 
  <code>strFn</code> that is created externally, 
  you MUST free this yourself.
  @param fn the <code>wordPagesFn</code> to use.
  @param strFn pass in the <code>strFn</code> to use.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*setStrFn)(wordPagesFn fn, strFn strFn);
  /** Free a wordPages, free up the memory.
  Use <code>void</code> to provide customizable function 
  for other library, so they can free memory of similar struct 
  through commond function call.
  i.e. it is NOT declared as 
  "<code>void (*free)(wordPages *aWordPagesP);</code>", 
  or NOT using type <code>wordPages</code>.
  @param aWordPagesP pass in the address of <code>wordPages</code> to be free.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*free)(void **aWordPagesP);
  /** Free a wordPagesFn, free up the memory.
  @param fnP pass in the address of <code>wordPagesFn</code> to be free.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*freeFn)(wordPagesFn *fnP);
  /** Set properties of the <code>wordPages</code>, 
  function provide for possible increase in processing speed.
  The page is NOT added but will overide pointer reference 
  of the 1st page in the list or array.
  Will free memory of previous <code>word</code> and 
  previous 1st page in the list or array.
  Will store a cloned copy of the word & the page passed in
  NOT the original.
  @param fn the <code>wordPagesFn</code> to use.
  @param aWordPages pass in the wordPages.
  @param word pass in the word.
  @param aPage the page number.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*setWordPages)(wordPagesFn fn, wordPages aWordPages, 
      const char *word, const char *aPage);
  /** Set properties of the <code>wordPages</code>, 
  function provide for possible increase in processing speed.
  The page is NOT added but will overide pointer reference 
  of the 1st page in the list or array.
  Will free memory of previous <code>word</code> and 
  previous 1st page in the list or array.
  Will store a cloned copy of the word & the page passed in
  NOT the original.
  @param fn the <code>wordPagesFn</code> to use.
  @param aWordPages pass in the wordPages.
  @param word pass in the word.
  @param wordLen the length of the <code>word</code>.
  @param aPage the page number.
  @return <code>true</code> if successfully otherwise <code>false</code>.
  */
  boolean (*setWordPagesWith)(wordPagesFn fn, wordPages aWordPages, 
      const char *word, const unsigned int wordLen, const char *aPage);
  /* specific operation */
  /** Get the word from this wordPages, 
  function provide for possible increase in processing speed. 
  This is not a cloned string but 
  what is inside this <code>wordPages</code>.
  WARNING: <code>wordPages</code> will free its own memory 
  if it still have reference to any of its data.
  Know what you're doing, misuse of function could lead to program crashes.
  @param aWordPages pass in the wordPages.
  @return the word, or <code>NULL</code> if failure.
  */
  char *(*getWord)(const wordPages aWordPages);
  /** Get a copy of the word (clone) from this wordPages.
  <p>Since this string is <code>malloc(..)</code>, to avoid memory leak
  it should be freed when no longer needed with a call to 
  <code>free(void *)</code>.
  </p>
  @param fn the <code>wordPagesFn</code> to use.
  @param aWordPages pass in the wordPages.
  @return the word, or <code>NULL</code> if failure.
  */
  char *(*getWordClone)(wordPagesFn fn, 
      const wordPages aWordPages);
  /** Get a copy of the pages from this wordPages,
  function provide for possible increase in processing speed. 
  This is not a cloned string but 
  what is inside this <code>wordPages</code>.
  WARNING: <code>wordPages</code> will free its own memory 
  if it still have reference to any of its data.
  Know what you're doing, misuse of function could lead to program crashes.
  @param aWordPages pass in the wordPages.
  @param pagesLen the length of the duplicated pages array.
  @return pointer to the pages array within this wordPages, 
    the returned array is cloned, or <code>NULL</code> if failure.
  */
  char **(*getPages)(
      const wordPages aWordPages, unsigned int *pagesLen);
  /** Get a copy of the pages from this wordPages.
  <p>Since this 2 dimension array 
  is <code>malloc(..)</code>, to avoid memory leak
  it should be freed when no longer needed with a call to 
  <code>free(void *)</code>.
  </p>
  @param fn the <code>wordPagesFn</code> to use.
  @param aWordPages pass in the wordPages.
  @param pagesLen the length of the duplicated pages array.
  @return pointer to the pages array within this wordPages, 
    the returned array is cloned, or <code>NULL</code> if failure.
  */
  char **(*getPagesClone)(wordPagesFn fn, 
      const wordPages aWordPages, unsigned int *pagesLen);
  /** Get the total number of pages stored within this wordPages.
  @param aWordPages pass in the wordPages.
  @return the number of pages from this wordPages or 
    -1 if failure occurs.
  */
  int (*getPagesLen)(const wordPages aWordPages);
  /** Get only the 1st page within this wordPages.
  function provide for possible increase in processing speed. 
  This is not a cloned string but 
  what is inside this <code>wordPages</code>.
  WARNING: <code>wordPages</code> will free its own memory 
  if it still have reference to any of its data.
  Know what you're doing, misuse of function could lead to program crashes.
  @param aWordPages pass in the wordPages.
  @return Return this page's page number or <code>NULL</code> if failure.
  */
  char *(*get1stPage)(const wordPages aWordPages);
  /** Get only the 1st page (a cloned copy) within this wordPages.
  <p>Since this string is <code>malloc(..)</code>, to avoid memory leak
  it should be freed when no longer needed with a call to 
  <code>free(void *)</code>.
  </p>
  @param fn the <code>wordPagesFn</code> to use.
  @param aWordPages pass in the wordPages.
  @return Return this page's page number or <code>NULL</code> if failure.
  */
  char *(*get1stPageClone)(wordPagesFn fn, const wordPages aWordPages);
  /** Is word the same as in this wordPages.
  Case sensitive and white space is also compared!
  <p>
  Uses standard <code>int strcmp(const char *str1, const char *str2);</code>
  for comparison.
  <code>str1</code> is word taken from <code>aWordPages</code>
  <code>str2</code> is the string <code>word</code>
  Returns zero if <code>str1</code> and <code>str2</code> are equal. 
    Returns less than zero or greater than zero 
    if <code>str1</code> is less than or 
    greater than <code>str2</code> respectively.
  </p>
  @param aWordPages pass in the wordPages.
  @param word pass in the word.
  @return true if same, otherwise false.
  */
  boolean (*isWord)(const wordPages aWordPages, const char *word);
  /** Compare word in these wordPages.
  Case sensitive and white space is also compared!
  <p>
  Uses standard <code>int strcmp(const char *str1, const char *str2);</code>
  for comparison.
  <code>str1</code> is the <code>word</code>.
  <code>str2</code> is word taken from <code>aWordPages</code>.
  Returns zero if <code>str1</code> and <code>str2</code> are equal. 
    Returns less than zero or greater than zero 
    if <code>str1</code> is less than or 
    greater than <code>str2</code> respectively.
  </p>
  @param word pass in the word.
  @param aWordPages pass in the wordPages.
  @return Returns zero if <code>word</code> and <code>aWordPages</code> are equal. 
    Returns less than zero or greater than zero 
    if <code>word</code> is less than or 
    greater than <code>aWordPages</code> respectively.
  */
  int (*compare)(const char *word, const wordPages aWordPages);
  /** Compare word in these wordPages.
  Case sensitive and white space is also compared!
  <p>Uses standard 
  <code>int strcmp(const char *str1, const char *str2);</code>
  for comparison.
  <code>str1</code> is word taken from <code>aWordPages1</code>.
  <code>str2</code> is word taken from <code>aWordPages2</code>.
  </p>
  @param aWordPages1 pass in the wordPages as <code>void *</code>.
  @param aWordPages2 pass in the wordPages as <code>void *</code>.
  @return Returns <code>g_replyEqual</code> if 
    <code>str1</code> and <code>str2</code> are equal. 
    Returns <code>g_replyLesser</code> or <code>g_replyGreater</code>
    if <code>str1</code> is less than or 
    greater than <code>str2</code> respectively.
    Otherwise <code>g_replyFail</code> for failure.
  */
  g_reply (*compareWordPages)(const void *aWordPages1, 
      const void *aWordPages2);
  /** Add a page into this wordPages. 
  If page already exist, this page will be ignored (no duplicates), success is return.
  Will create another copy of this page (clone of), 
  will NOT use the passed in string.
  @param fn the <code>wordPagesFn</code> to use.
  @param aWordPages pass in the wordPages.
  @param aPage the page number to add.
  @return <code>wpSuccess</code> if successful, <code>wpFail</code> for failure 
    or <code>wpIgnored</code> if <code>page</code> already exist.
  */
  wpState (*addPage)(wordPagesFn fn, 
      wordPages aWordPages, const char *aPage);
};

/** Create a <code>wordPagesFn</code> that 
provide wordPages function pointers.
@return a working struct of <code>wordPages</code> function pointers.
*/
wordPagesFn wordPages_createFn(void);

#endif /* _WORDPAGES_H */
